package com.oot2d.entity;

import org.newdawn.slick.*;
import com.oot2d.util.File;
import com.oot2d.util.InputManager;
import com.oot2d.util.WorldManager;

import java.util.ArrayList;
import java.util.Random;

public class Player extends NPC {
    //Debug?
    public static Player instance;

    private PlayerState state;
    private WeaponAABB[] swordHit;
    private Navi navi;
    private Sound[] sword;
    private Sound[] walk;
    private Sound[] tar;
    private Random dice;
    private int delay;

    private ArrayList<NPC> nearbyNPCs;
    private NPC target;

    private float maxMagic = File.maxMagic;
    private float magic = File.magic;

    public Player()
    {
        super("link_child", 48, 48, false, File.maxHealth, 16);

        //Movement animations
        anims[0] = new Animation(sheet, 0, 1, 6, 1, true, 40, false);
        anims[1] = new Animation(sheet, 0, 2, 6, 2, true, 40, false);
        anims[2] = new Animation(sheet, 0, 3, 6, 3, true, 40, false);
        anims[3] = new Animation(sheet, 0, 4, 6, 4, true, 40, false);

        //Sword animations
        anims[4] = new Animation(sheet, 0, 5, 8, 5, true, 28, false);
        anims[5] = new Animation(sheet, 0, 6, 8, 6, true, 28, false);
        anims[6] = new Animation(sheet, 0, 7, 8, 7, true, 28, false);
        anims[7] = new Animation(sheet, 0, 8, 8, 8, true, 28, false);

        //Disable looping for sword animations
        for (int i = 4; i < 8; i++) {
            anims[i].setLooping(false);
            anims[i].stopAt(8);
        }

        swordHit = new WeaponAABB[4];
        state = PlayerState.Idle;
        dir = Direction.Down;

        aabb = new AABB(7, 7, 0, 4, this);

        navi = new Navi();

        //Test
        health = File.health;

        //Test Sounds
        try {
            sword = new Sound[] {
                    new Sound("res/music/Link_Sword1.ogg"),
                    new Sound("res/music/Link_Sword2.ogg"),
                    new Sound("res/music/Link_Sword3.ogg")
            };

            walk = new Sound[] {
                    new Sound("res/music/OOT_Steps_Grass1.ogg")
            };

            tar = new Sound[] {
                    new Sound("res/music/target_select_unfriendly.ogg"),
                    new Sound("res/music/target_select_friendly.ogg"),
                    new Sound("res/music/target_deselect.ogg")
            };
        } catch (SlickException e) {
            System.err.print(e);
        }
        delay = 0;

        //Random numbers
        dice = new Random();

        nearbyNPCs = new ArrayList<NPC>();

        instance = this;
    }

    public void spawn()
    {
        setPos(WorldManager.currentWorld.getSpawn());
    }

    public float getMagic()
    {
        return magic;
    }

    public float getMaxMagic()
    {
        return maxMagic;
    }

    public float getX()
    {
        return x;
    }

    public float getY()
    {
        return y;
    }

    public NPC getTarget()
    {
        return target;
    }

    public void zTarget()
    {
        if (target != null) {
            tar[2].play(1.0f, 0.3f);
            target = null;
            return;
        }

        nearbyNPCs = WorldManager.queryNPCs(x - 240.0f, y - 160.0f, 480.0f, 320.0f, z);

        float dis = Float.MAX_VALUE;
        for (NPC n : nearbyNPCs) {
            float d = (float)Math.abs(Math.sqrt((n.getCenterX() - x) * (n.getCenterX() - x) +
                    (n.getCenterY() - y) * (n.getCenterY() - y)));
            if (d < dis) {
                dis = d;
                target = n;
            }
        }

        if (target != null) {
            System.out.println(target.attackable);
            if (target.attackable)
                tar[0].play(1.0f, 0.3f);
            else
                tar[1].play(1.0f, 0.3f);
        }
    }

    private void attack()
    {
        state = PlayerState.Attacking;
        vel.x = 0.0f;
        vel.y = 0.0f;

        //Start animation
        currAnim = anims[4 + dir.val()];
        currAnim.stop();
        currAnim.setCurrentFrame(0);
        currAnim.start();

        //Random attack sound
        sword[dice.nextInt(3)].play(1.0f, .2f);
    }

    private void stopAllAnims()
    {
        for (int i = 0; i < 8; i++) {
            anims[i].stop();
            anims[i].setCurrentFrame(0);
        }
    }

    public void update(int d)
    {
        navi.update(d);

        if (currAnim != null)
            currAnim.update(d);

        //New attack
        if (InputManager.mouse1()) {
            attack();
        }

        //Handle current attack
        if (state == PlayerState.Attacking) {
            //Check if the animation is done
            if (currAnim.isStopped()) {
                currAnim.stop();
                currAnim.setCurrentFrame(0);
                state = PlayerState.Idle;
            }

            //If not, check sword collision
            if (currAnim.getFrame() == 5) {
                //Handle sword collision
                //swordHit[dir.val()].update();
            }

            return;

        } else {
            state = PlayerState.Idle;
            vel.x = 0.0f;
            vel.y = 0.0f;
        }

        //Z-targeting
        if (InputManager.tab())
            zTarget();

        //Sound Test
        if(InputManager.up() || InputManager.down() || InputManager.left() || InputManager.right()){
            delay +=  d;
            if(delay > 200) {
                walk[0].play(1.0f, .5f);
                delay = 0;
            }
        }

        //Movement
        if (InputManager.left()) {
            state = PlayerState.Moving;
            dir = Direction.Left;

            if (InputManager.up() || InputManager.down())
                vel.x = (float)((Math.sqrt(2) / 2.0f) * -0.1f);
            else
                vel.x = -0.1f;
        }

        if (InputManager.right()) {
            state = PlayerState.Moving;
            dir = Direction.Right;

            if (InputManager.up() || InputManager.down())
                vel.x = (float)((Math.sqrt(2) / 2.0f) * 0.1f);
            else
                vel.x = 0.1f;
        }

        if (InputManager.up()) {
            state = PlayerState.Moving;
            dir = Direction.Up;

            if (InputManager.left() || InputManager.right())
                vel.y = (float)((Math.sqrt(2) / 2.0f) * -0.1f);
            else
                vel.y = -0.1f;
        }

        if (InputManager.down()) {
            state = PlayerState.Moving;
            dir = Direction.Down;


            if (InputManager.left() || InputManager.right())
                vel.y = (float)((Math.sqrt(2) / 2.0f) * 0.1f);
            else
                vel.y = 0.1f;
        }

        //Handle collision
        aabb.update(d, true);

        x += (vel.x * d);
        y += (vel.y * d);

        if (state == PlayerState.Idle) {
            stopAllAnims();
        } else if (state == PlayerState.Moving) {
            currAnim = anims[dir.val()];
            if (currAnim.isStopped())
                currAnim.start();
        }
    }

    public void draw()
    {
        if (state == PlayerState.Idle) {
            sheet.startUse();
            sheet.getSubImage(dir.val(), 0).drawEmbedded(216.0f, 136.0f, 48.0f, 48.0f);
            sheet.endUse();
        } else {
            if (currAnim != null)
                currAnim.draw(216.0f, 136.0f, 48.0f, 48.0f);
        }

        navi.draw();
    }
}
